package com.vhall.component.service.vote;

import com.vhall.component.plugin.common.constant.RedisKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Set;
import java.util.concurrent.TimeUnit;


/**
 * @author longzhen.gong
 * @date 2021/7/8 11:01
 */
@Slf4j
@Component
public class VoteAnswerSyncTask {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private VoteRoomService voteRoomService;



    /**
     * 投票回答异地落库
     */
    // @Scheduled(cron = "${vhall.vote.answer-sync:0/5 * * * * ?}")
    public void execute() {
        String key = "vhall.vote.answer-sync";
        try {
            //存在隐患，如果投票量大。可能30s处理不完成。可以改用队列.  而且存在丢失数据风险
            if (Boolean.FALSE.equals(stringRedisTemplate.opsForValue()
                    .setIfAbsent(RedisKey.VOTE_ANSWER_SYNC_LOCK, "1", 60, TimeUnit.SECONDS))) {
                return;
            }
            String queue = RedisKey.VOTE_ANSWER_ROOMS_QUEUE;
            Set<ZSetOperations.TypedTuple<String>> roomSet = stringRedisTemplate.opsForZSet().rangeWithScores(queue, 0, 100);
            if (roomSet == null || roomSet.isEmpty()) {
                log.debug("投票队列消费 队列无数据,queue:{}", queue);
                return;
            }
            for (ZSetOperations.TypedTuple<String> stringTypedTuple : roomSet) {
                String room = stringTypedTuple.getValue();
                Double score = stringTypedTuple.getScore();
                score = score == null ? 0 : score;
                String answerKey = RedisKey.VOTE_ANSWER_LIST_QUEUE + room;
                if (score.longValue() < LocalDateTime.now().plusDays(-1).toEpochSecond(ZoneOffset.of("+8")) && (
                        Boolean.FALSE.equals(stringRedisTemplate.hasKey(answerKey))
                                || stringRedisTemplate.opsForList().size(answerKey) == 0)) {
                    stringRedisTemplate.opsForZSet().remove(queue, room);
                    stringRedisTemplate.expire(answerKey, 0, TimeUnit.SECONDS);
                    continue;
                }
                while (true) {
                    //服务重启会丢失数据 最好改用消息队列 或者同步操作
                    String param = stringRedisTemplate.opsForList().leftPop(answerKey);
                    long start = System.currentTimeMillis();
                    if (null == param || "null".equals(param)) {
                        //延时队列 存储所有待结束投票数据 90分钟  投票最长时间1小时。这里设置70分钟
                        stringRedisTemplate.expire(answerKey, 70, TimeUnit.MINUTES);
                        break;
                    }
                    log.info("投票队列消费开始-queue,开始时间={},参数:{}", LocalDateTime.now(), param);
                    voteRoomService.answerToDb(param);
                    log.info("投票队列消费成功-queue,耗时:{}", System.currentTimeMillis() - start);
                }
            }
        } catch (Exception ex) {
            log.error("投票队列消费失败:", ex);
        } finally {
            stringRedisTemplate.expire(RedisKey.VOTE_ANSWER_SYNC_LOCK, 0, TimeUnit.SECONDS);
        }

    }

}
